#include <iostream>

// 运算符重载
class point{
    //重载中使用类的私有对象时，添加友元全局函数    
public:
    int x;
    int y;
    int *id;

    point() : x(0),y(0), id(new int(0)) {};
    point(int x, int y, int id);
    point(const point &p);
    ~point();
    //成员函数重载
    point operator+(point &p1);
    // 不能用成员函数重载左移运算符，因为无法实现cout在左侧
    // point operator<<();
    point& operator++();
    point operator++(int);
    point& operator=(const point &p);
    bool operator==(const point &p);
    bool operator!=(const point &p);
    std::string operator()();   // 仿函数

};

point::point(int x, int y, int id){
    this->x = x;
    this->y = y;
    this->id = new int(id);
}
point::point(const point &p){
    this->x = p.x;
    this->y = p.y;
    this->id = new int(*p.id);
}
point::~point(){
    if(id != NULL){
        delete id;
        id = NULL;
    }
}
point point::operator+(point &p1){  // 加法重载
    point p;
    p.x = this->x + p1.x;
    p.y = this->y + p1.y;
    return p;
}
point& point::operator++(){      // 前置递增重载
    x++;
    y++;
    return *this;
}
point point::operator++(int){   // 后置递增重载
    // 不加&是因为后置递增是先输出值，然后再++
    point temp = *this;
    x++;
    y++;
    return temp;
}   
point& point::operator=(const point &p){    // 赋值运算符重载
    this->x = p.x;
    this->y = p.y;
    if(this->id != NULL){   //判断this->id是否为空，不为空则释放内存
        delete this->id;
        this->id = NULL;
    }
    this->id = new int(*p.id);
    return *this;
}
bool point::operator==(const point &p){    // 关系运算符重载
    if(this->x == p.x && this->y == p.y) return 1;
    else return 0; 
}
bool point::operator!=(const point &p){    // 关系运算符重载
    if(this->x != p.x && this->y != p.y) return 1;
    else return 0; 
}
std::string point::operator()(){    //函数调用运算符重载  
    std::string s = "{ " + std::to_string(x) + ", " + 
                    std::to_string(y) + ", " + 
                    std::to_string(*id) + " }";
    return s;
}

//全局函数重载
point operator+(const point &p1, const point &p2){  // 加法重载
    point p;
    p.x = p1.x + p2.x;
    p.y = p1.y + p2.y;
    return p;
}
std::ostream & operator<<(std::ostream &cout, const point &p){     //左移重载
    //为什么加const？
    //因为后置递增是先输出，后++
    //后置递增函数的函数类型是point，即使用值传递的方式传递参数，不同于前置递增函数使用引用传递
    //非const引用只能绑定到左值（有名字的对象），不能绑定到临时对象（右值）
    std::cout<<"("<<p.x<<", "<<p.y<<", "<< *p.id <<")";
    return cout;
}
int main()
{
    point p1(2, 4, 1);
    point p2(3, 1, 2);
    point p3(5, 5, 3);
    point p = p1 + p2 + p3;
    // 成员函数重载本质
    // point p = p1.operator+(p2);
    // 全局函数重载本质
    // point p = operator+(p1, p2);

    // std::cout<< "p (x ,y) = (" << p.x << "," << p.y << ")"<< std::endl;
    // std::cout<< ++(++p) <<std::endl;
    // std::cout<< p++ <<std::endl;

    // p1 = p2 = p3;
    // std::cout<< p1 <<std::endl;
    // std::cout<< p2 <<std::endl;
    // std::cout<< p3 <<std::endl;
    
    // if(p1 == p2) std::cout<< "相等" << std::endl;
    // else std::cout<< "不相等" << std::endl;

    std::cout<< p1() <<std::endl;
    //匿名函数对象
    std::cout<< point()() <<std::endl;

    return 0;
}